#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>

#include "include/scene.h"
#include "include/sphere.h"
#include "include/spheretexture.h"
#include "include/object.h"
#include "include/plane.h"
#include "include/planecicle.h"
#include "include/quadric.h"
#include "include/quadrictexture.h"
#include "include/triangle.h"
#include "include/triangletexture.h"

#include "include/directional_light.h"
#include "include/point_light.h"

#include "my/include/camera.h"
#include "my/include/scaling.h"
#include "my/include/translation.h"
#include "my/include/rotation.h"

#define XSIZE 512
#define YSIZE 512

#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255

PPMImage *image;


Colour frame_buffer[YSIZE][XSIZE];

float frand() {
	int x;
	float f;

	x = rand();
	f = (float) (x & 0xffff);
	f = f / 65536.0;

	return f;
}
long long current_timestamp() {
	struct timeval te;
	gettimeofday(&te, NULL); // get current time
	long long milliseconds = te.tv_sec * 1000LL + te.tv_usec / 1000; // caculate milliseconds
	// printf("milliseconds: %lld\n", milliseconds);
	return milliseconds;
}

void getcurrentTimeString(char *buffer) {
	time_t timer;
	//	char buffer[25];
	struct tm* tm_info;

	time(&timer);
	tm_info = localtime(&timer);

	strftime(buffer, 25, "%Y-%m-%d-%H-%M-%S", tm_info);
}
void write_framebuffer() {
	int x, y;
	float r, g, b;
	FILE *f;
	char filename[80];
	//sprintf(filename,"%lld.ppm",current_timestamp());
	getcurrentTimeString(filename);
	sprintf(filename, "%s.ppm", filename);
	f = fopen(filename, "w");

	fprintf(f, "P3\n%d %d\n255\n", XSIZE, YSIZE);

	for (y = YSIZE - 1; y >= 0; y -= 1) {
		for (x = 0; x < XSIZE; x += 1) {
			r = 255.0 * frame_buffer[y][x].getRed();
			g = 255.0 * frame_buffer[y][x].getGreen();
			b = 255.0 * frame_buffer[y][x].getBlue();
			if (r > 255.0)
				r = 255.0;
			if (g > 255.0)
				g = 255.0;
			if (b > 255.0)
				b = 255.0;
			fprintf(f, "%d %d %d\n", (int) r, (int) g, (int) b);
		}
	}
}


PPMImage *readPPM(const char *filename) {
	char buff[16];
	PPMImage *img;
	FILE *fp;
	int c, rgb_comp_color;
	//open PPM file for reading
	fp = fopen(filename, "rb");
	if (!fp) {
		fprintf(stderr, "Unable to open file '%s'\n", filename);
		exit(1);
	}

	//read image format
	if (!fgets(buff, sizeof(buff), fp)) {
		perror(filename);
		exit(1);
	}

	//check the image format
	if (buff[0] != 'P' || buff[1] != '6') {
		fprintf(stderr, "Invalid image format (must be 'P3')\n");
		exit(1);
	}

	//alloc memory form image
	img = (PPMImage *) malloc(sizeof(PPMImage));
	if (!img) {
		fprintf(stderr, "Unable to allocate memory\n");
		exit(1);
	}

	//check for comments
	c = getc(fp);
	while (c == '#') {
		while (getc(fp) != '\n')
			;
		c = getc(fp);
	}

	ungetc(c, fp);
	//read image size information
	if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
		fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
		exit(1);
	}

	//read rgb component
	if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
		fprintf(stderr, "Invalid rgb component (error loading '%s')\n",
				filename);
		exit(1);
	}

	//check rgb component depth
	if (rgb_comp_color != RGB_COMPONENT_COLOR) {
		fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
		exit(1);
	}

	while (fgetc(fp) != '\n')
		;
	//memory allocation for pixel data
	img->data = (PPMPixel*) malloc(img->x * img->y * sizeof(PPMPixel));

	if (!img) {
		fprintf(stderr, "Unable to allocate memory\n");
		exit(1);
	}

	//read pixel data from file
	if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
		fprintf(stderr, "Error loading image '%s'\n", filename);
		exit(1);
	}

	fclose(fp);
	return img;
}
void clear_framebuffer() {
	int x, y;

	for (y = 0; y < YSIZE; y += 1) {
		for (x = 0; x < XSIZE; x += 1) {
			frame_buffer[y][x].clear();
		}
	}
}


void addPlane2(Scene *scene) {
	Plane *plane;
	Vector nor_vec;
	nor_vec.set(0, 0, -1);
	Vertex a_vert;
	a_vert.set(0, -0.01, 30, 1);
	plane = new Plane(a_vert, nor_vec);
	Material *mx;
	mx = new Material();
	double cr = 0.1;
	double cg = 0.1;
	double cb = 0.1;

	mx->ka.red = cr * 0.1;
	mx->ka.green = cg * 0.1;
	mx->ka.blue = cb * 0.1;
	mx->kd.red = cr * 0.5;
	mx->kd.green = cg * 0.5;
	mx->kd.blue = cb * 0.5;
	mx->kr.red = 0.0;
	mx->kr.green = 0.0;
	mx->kr.blue = 0.0;
	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;
	mx->kt.red = 0.0;
	mx->kt.green = 0.0;
	mx->kt.blue = 0.0;
	mx->n = 400.0;

	// set spheres material
	plane->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*plane);
}

void addPlane(Scene *scene) {
	Plane *plane;
	double ca, cr, cg, cb;
	Vector nor_vec;
	nor_vec.set(0, 1, 0);
	Vertex a_vert;
	a_vert.set(0, -0.01, 0, 1);
	plane = new Plane(a_vert, nor_vec);
	Material *mx;
	mx = new Material();

	cr = 0.1;
	cg = 0.1;
	cb = 0.1;
	ca = frand();

	mx->ka.red = cr * 0.1;
	mx->ka.green = cg * 0.1;
	mx->ka.blue = cb * 0.1;
	mx->kd.red = cr * 0.5;
	mx->kd.green = cg * 0.5;
	mx->kd.blue = cb * 0.5;
	mx->kr.red = 0.1;
	mx->kr.green = 0.1;
	mx->kr.blue = 0.1;

	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;
	mx->kt.red = 0.0;
	mx->kt.green = 0.0;
	mx->kt.blue = 0.0;
	mx->n = 400.0;

	// set spheres material
	plane->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*plane);
}

void addBox(Scene *scene) {
	Triangle *triangle;
	Vertex aa;
	Vertex bb;
	Vertex cc;
	aa.set(2, 0.3, 1, 0);
	bb.set(0, 0, 1, 0);
	cc.set(2, 0, 1, 0);
	triangle = new Triangle(aa, bb, cc);
	triangle->refraction = 1.52;

	Triangle *triangle1;
	aa.set(2, 0.3, 1, 0);
	bb.set(0, 0.3, 1, 0);
	cc.set(0, 0, 1, 0);
	triangle1 = new Triangle(aa, bb, cc);
	triangle1->refraction = 1.52;

	Material *mx;
	mx = new Material();

	mx->ka.red = 0.0;//cr * 0.1;
	mx->ka.green = 0.0;//cg * 0.1;
	mx->ka.blue = 0.0;//cb * 0.1;

	mx->kd.red = 0.0;//cr * 0.1;
	mx->kd.green = 0.0;//cg * 0.1;
	mx->kd.blue = 0.0;//cb * 0.1;

	mx->kr.red = 0.5;
	mx->kr.green = 0.5;
	mx->kr.blue = 0.5;

	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;

	mx->kt.red = 1.0;
	mx->kt.green = 1.0;
	mx->kt.blue = 1.0;
	mx->n = 100.0;

	// set spheres material
	triangle->setMaterial(mx);
	triangle1->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*triangle);
	scene->addObject(*triangle1);

}

void addTriangle(Scene *scene) {
	Triangle *triangle;
	double ca, cr, cg, cb;
	Vertex aa;
	aa.set(1, 1, 5, 0);
	Vertex bb;
	bb.set(-1.0, 0, 5, 0);
	Vertex cc;
	cc.set(1, 0, 5, 0);
	triangle = new Triangle(aa, bb, cc);
	//	triangle->refraction = 1.52;
	Material *mx;
	mx = new Material();

	cr = frand();
	cg = frand();
	cb = frand();
	ca = frand();

	mx->ka.red = 0.3;//cr * 0.1;
	mx->ka.green = 0.3;//cg * 0.1;
	mx->ka.blue = 0.0;//cb * 0.1;

	mx->kd.red = 0.0;//cr * 0.1;
	mx->kd.green = 0.0;//cg * 0.1;
	mx->kd.blue = 0.0;//cb * 0.1;

	mx->kr.red = 0.5;
	mx->kr.green = 0.5;
	mx->kr.blue = 0.5;

	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;

	mx->kt.red = 0.0;
	mx->kt.green = 0.0;
	mx->kt.blue = 0.0;
	mx->n = 100.0;

	// set spheres material
	triangle->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*triangle);

}



void addTriangleTexture(Scene *scene) {
	TriangleTexture *triangle;
	double ca, cr, cg, cb;
	Vertex aa;
	aa.set(-2, 1.6, 5, 0);
	Vertex bb;
	bb.set(-5, 0, 5, 0);
	Vertex cc;
	cc.set(-2, 0, 5, 0);
	triangle = new TriangleTexture(aa, bb, cc,image);
	//	triangle->refraction = 1.52;
	Material *mx;
	mx = new Material();

	cr = frand();
	cg = frand();
	cb = frand();
	ca = frand();

	mx->ka.red = 0.3;//cr * 0.1;
	mx->ka.green = 0.3;//cg * 0.1;
	mx->ka.blue = 0.0;//cb * 0.1;

	mx->kd.red = 0.0;//cr * 0.1;
	mx->kd.green = 0.0;//cg * 0.1;
	mx->kd.blue = 0.0;//cb * 0.1;

	mx->kr.red = 0.5;
	mx->kr.green = 0.5;
	mx->kr.blue = 0.5;

	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;

	mx->kt.red = 0.0;
	mx->kt.green = 0.0;
	mx->kt.blue = 0.0;
	mx->n = 100.0;

	// set spheres material
	triangle->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*triangle);

}

void addQuadricEllipsoid(Scene *scene) {
	Quadric *quadric;
	double ca, cr, cg, cb;
	Vertex p;
	//	p.set(1,0.1,3,1);//p.set(-0.3737030029296875,0.23406982421875,1.578338623046875,1);
	p.set(0.1, 0, 0.1, 1.0);
//	p.set(-0.2, 0.1, 0.7, 1.0);
	quadric = new Quadric(1, 0.08, 1, 0, 0, 0, 0, 0, 0, -0.00006, p, 0); //(1,-1,1,0,0,0,0,0,0,0,p,0.2);
	quadric->typei = 31;
	Material *mx;
	mx = new Material();

	cr = 0.2;
	cg = 0.1;
	cb = 0.8;
	ca = frand();

	mx->ka.red = cr;
	mx->ka.green = cg;
	mx->ka.blue = cb;
	mx->kd.red = cr * 0.5;
	mx->kd.green = cg * 0.5;
	mx->kd.blue = cb * 0.5;
	mx->kr.red = 0.5;
	mx->kr.green = 0.5;
	mx->kr.blue = 0.5;
	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;
	mx->kt.red = 0.5;
	mx->kt.green = 0.5;
	mx->kt.blue = 0.5;
	mx->n = 400.0;

	// set spheres material
	quadric->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*quadric);
}

void addQuadricCone(Scene *scene) {
	Quadric *quadric;
	double ca, cr, cg, cb;
	Vertex p;
	//	p.set(1,0.1,3,1);//p.set(-0.3737030029296875,0.23406982421875,1.578338623046875,1);
	p.set(-0.0, 0.1, 0.6, 1);
	double h = 0.042;
	quadric = new Quadric(1, -6, 1, 0, 0, 0, 0, 0, 0, 0, p, h); //(1,-1,1,0,0,0,0,0,0,0,p,0.2);
	quadric->refraction = 2.5;
	quadric->typei = 32;
	Material *mx;
	mx = new Material();

	double r = 0.16;
	double g = 0.12;
//		r = r/10.0;
//		g = r/10.0;
	mx->ka.red = r;
	mx->ka.green = g;
	mx->ka.blue = 0.0;

	mx->kd.red = r;
	mx->kd.green = g;
	mx->kd.blue = 0.0;

	mx->kr.red = r;
	mx->kr.green = g;
	mx->kr.blue = 0.0;

	mx->ks.red = r;
	mx->ks.green = g;
	mx->ks.blue = 0.0;

	mx->kt.red = 1;
	mx->kt.green = 1;
	mx->kt.blue = 1;
	mx->n = 400.0;

	// set spheres material
	quadric->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*quadric);
}
void addQuadricConeW(Scene *scene) {
	Quadric *quadric;
	double ca, cr, cg, cb;
	Vertex p;
	//	p.set(1,0.1,3,1);//p.set(-0.3737030029296875,0.23406982421875,1.578338623046875,1);
	p.set(-0.0, 0.111, 0.6, 1);
	double h = 0.02;
	quadric = new Quadric(1, -6, 1, 0, 0, 0, 0, 0, 0, 0, p, h); //(1,-1,1,0,0,0,0,0,0,0,p,0.2);
//	quadric->refraction = 1.8;
	quadric->typei = 32;
	Material *mx;
	mx = new Material();

	double r = 0.8;
	double g = 0.6;
//		r = r/10.0;
//		g = r/10.0;
	mx->ka.red = r;
	mx->ka.green = g;
	mx->ka.blue = 0.0;

	mx->kd.red = r;
	mx->kd.green = g;
	mx->kd.blue = 0.0;

	mx->kr.red = r;
	mx->kr.green = g;
	mx->kr.blue = 0.0;

	mx->ks.red = r;
	mx->ks.green = g;
	mx->ks.blue = 0.0;

	mx->kt.red = 1;
	mx->kt.green = 1;
	mx->kt.blue = 1;
	mx->n = 400.0;

	// set spheres material
	quadric->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*quadric);
}

void addQuadricCone2(Scene *scene) {
	Quadric *quadric;
	double ca, cr, cg, cb;
	Vertex p;
	//	p.set(1,0.1,3,1);//p.set(-0.3737030029296875,0.23406982421875,1.578338623046875,1);
	p.set(-0.0, 0.012, 0.6, 1);
	double h = -0.016;
	quadric = new Quadric(0.7, -11, 2, 0, 0, 0, 0, 0, 0, 0, p, h); //(1,-1,1,0,0,0,0,0,0,0,p,0.2);
	quadric->refraction = 1.8;
	quadric->typei = 32;
	Material *mx;
	mx = new Material();

	cr = 0.8;
	cg = 0.6;
	cb = 0.0;
	ca = frand();

	double r = 0.16;
	double g = 0.12;
//		r = r/10.0;
//		g = r/10.0;
	mx->ka.red = r;
	mx->ka.green = g;
	mx->ka.blue = 0.0;

	mx->kd.red = r;
	mx->kd.green = g;
	mx->kd.blue = 0.0;

	mx->kr.red = r;
	mx->kr.green = g;
	mx->kr.blue = 0.0;

	mx->ks.red = r;
	mx->ks.green = g;
	mx->ks.blue = 0.0;

	mx->kt.red = 1;
	mx->kt.green = 1;
	mx->kt.blue = 1;
	mx->n = 400.0;

	// set spheres material
	quadric->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*quadric);
}

void addQuadricCylinder(Scene *scene) {
	Quadric *quadric;
	double ca, cr, cg, cb;
	Vertex p;
	//	p.set(1,0.1,3,1);//p.set(-0.3737030029296875,0.23406982421875,1.578338623046875,1);
	p.set(-0.39, -0.2, 0.4, 1);

	double j;
	double r = 0.03;
	double h = 0.2;
	j = -r * r;
	quadric = new Quadric(1, 0, 1, 0, 0, 0, 0, 0, 0, j, p, h);//A=C=1,B=D=E=F=G=H=I=0,J=r,P=offset,H=height
	//(1,-1,1,0,0,0,0,0,0,0,p,0.2);
	quadric->typei = 33;

	Material *mx;
	mx = new Material();

	cr = 0.6;
	cg = 0.1;
	cb = 0.5;
	ca = frand();

	mx->ka.red = cr;
	mx->ka.green = cg;
	mx->ka.blue = cb;
	mx->kd.red = cr * 0.5;
	mx->kd.green = cg * 0.5;
	mx->kd.blue = cb * 0.5;
	mx->kr.red = 0.5;
	mx->kr.green = 0.5;
	mx->kr.blue = 0.5;
	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;
	mx->kt.red = 0.0;
	mx->kt.green = 0.0;
	mx->kt.blue = 0.0;
	mx->n = 400.0;

	// set spheres material
	quadric->setMaterial(mx);

	PlaneCicle *plane;
	double ca1, cr1, cg1, cb1;
	Vector nor_vec;
	nor_vec.set(0, 1, 0);
	Vertex a_vert = p;
	plane = new PlaneCicle(a_vert, nor_vec, r);

	PlaneCicle *planebottom;
	a_vert.set(p.x, p.y + h, p.z, p.w);
	planebottom = new PlaneCicle(a_vert, nor_vec, r);

	plane->setMaterial(mx);
	planebottom->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*plane);
	scene->addObject(*planebottom);
	scene->addObject(*quadric);
}

void addQuadricCylinderTexture(Scene *scene) {
	QuadricTexture *quadric;
	double ca, cr, cg, cb;
	Vertex p;
	//	p.set(1,0.1,3,1);//p.set(-0.3737030029296875,0.23406982421875,1.578338623046875,1);
	p.set(0.46, -0.1, 0.4, 1);

	double j;
	double r = 0.04;
	double h = 0.15;
	j = -r * r;
	quadric = new QuadricTexture(1, 0, 1, 0, 0, 0, 0, 0, 0, j, p, h,image); //(1,-1,1,0,0,0,0,0,0,0,p,0.2);
	quadric->typei = 34;

	Material *mx;
	mx = new Material();

	cr = 0.6;
	cg = 0.1;
	cb = 0.5;
	ca = frand();

	mx->ka.red = cr;
	mx->ka.green = cg;
	mx->ka.blue = cb;
	mx->kd.red = cr * 0.5;
	mx->kd.green = cg * 0.5;
	mx->kd.blue = cb * 0.5;
	mx->kr.red = 0.5;
	mx->kr.green = 0.5;
	mx->kr.blue = 0.5;
	mx->ks.red = 0.5;
	mx->ks.green = 0.5;
	mx->ks.blue = 0.5;
	mx->kt.red = 1.0;
	mx->kt.green = 1.0;
	mx->kt.blue = 1.0;
	mx->n = 400.0;

	// set spheres material
	quadric->setMaterial(mx);

	PlaneCicle *plane;
	double ca1, cr1, cg1, cb1;
	Vector nor_vec;
	nor_vec.set(0, 1, 0);
	Vertex a_vert = p;
	plane = new PlaneCicle(a_vert, nor_vec, r);

	PlaneCicle *planebottom;
	a_vert.set(p.x, p.y + h, p.z, p.w);
	planebottom = new PlaneCicle(a_vert, nor_vec, r);

	plane->setMaterial(mx);
	planebottom->setMaterial(mx);

	// as sphere to scene
	scene->addObject(*plane);
	scene->addObject(*planebottom);
	scene->addObject(*quadric);
}



// The main raytacing entry point.

void addSphereRed(Scene *scene) {
	Sphere *s;
	Material *m;
	Vertex p;
	// position
	p.set(0.9, 0.2, 1.5, 1.0);
	s = new Sphere(p, 0.3);
	//	s->refraction = 1.53;// open refraction by set a refraction value. 1.53 is glass. 1.3 is water.
	// create new material with shared random Ka and Kd
	m = new Material();
	m->ka.red = 0.2;
	m->ka.green = 0.0;
	m->ka.blue = 0.0;
	m->kd.red = 0.0;
	m->kd.green = 0.0;
	m->kd.blue = 0.0;

	m->kr.red = 0.5;
	m->kr.green = 0.5;
	m->kr.blue = 0.5;

	m->ks.red = 0.5;
	m->ks.green = 0.5;
	m->ks.blue = 0.5;

	m->kt.red = 1;
	m->kt.green = 1;
	m->kt.blue = 1;

	m->n = 400.0;
	// set spheres material
	s->setMaterial(m);
	// as sphere to scene
	scene->addObject(*s);
}

void addSphereBlue(Scene *scene) {
	Sphere *s;
	Material *m;
	Vertex p;
	// position
	p.set(0.2, 0.03, 0.7, 1.0);
	s = new Sphere(p, 0.1);
	//	s->refraction = 1.53;// open refraction by set a refraction value. 1.53 is glass. 1.3 is water.
	// create new material with shared random Ka and Kd
	m = new Material();
	m->ka.red = 0.0;
	m->ka.green = 0.0;
	m->ka.blue = 0.6;
	m->kd.red = 0.0;
	m->kd.green = 0.0;
	m->kd.blue = 0.0;

	m->kr.red = 0.5;
	m->kr.green = 0.5;
	m->kr.blue = 0.5;

	m->ks.red = 0.5;
	m->ks.green = 0.5;
	m->ks.blue = 0.5;

	m->kt.red = 1;
	m->kt.green = 1;
	m->kt.blue = 1;

	m->n = 400.0;
	// set spheres material
	s->setMaterial(m);
	// as sphere to scene
	scene->addObject(*s);
}

void addSphereGreen(Scene *scene) {
	Sphere *s;
	Material *m;
	Vertex p;
	// position
	p.set(-0.2, 0.1, 0.7, 1.0);
	s = new Sphere(p, 0.1);
	//	s->refraction = 1.53;// open refraction by set a refraction value. 1.53 is glass. 1.3 is water.
	// create new material with shared random Ka and Kd
	m = new Material();
	m->ka.red = 0.0;
	m->ka.green = 0.41;
	m->ka.blue = 0.0;

	m->kd.red = 0.2;
	m->kd.green = 0.2;
	m->kd.blue = 0.2;

	m->kr.red = 0.1;
	m->kr.green = 0.1;
	m->kr.blue = 0.1;

	m->ks.red = 0.1;
	m->ks.green = 0.1;
	m->ks.blue = 0.1;

	m->kt.red = 0;
	m->kt.green = 0;
	m->kt.blue = 0;

	m->n = 400.0;
	// set spheres material
	s->setMaterial(m);
	// as sphere to scene
	scene->addObject(*s);
}

void addSphereTrans(Scene *scene) {
	for(int i = 0; i < 5; i++){

		Sphere *s;
		Material *m;
		Vertex p;
		// position
		double di = (double)i;
		double y = di* 0.019 + 0.02;
		p.set(-0.0, y, 0.6, 1.0);
		s = new Sphere(p, 0.01);
		s->refraction = 1.8;// open refraction by set a refraction value. 1.53 is glass. 1.3 is water.
		// create new material with shared random Ka and Kd
		m = new Material();
		double r = 0.16;
		double g = 0.12;
//		r = r/10.0;
//		g = r/10.0;
		m->ka.red = r;
		m->ka.green = g;
		m->ka.blue = 0.0;

		m->kd.red = r;
		m->kd.green = g;
		m->kd.blue = 0.0;

		m->kr.red = r;
		m->kr.green = g;
		m->kr.blue = 0.0;

		m->ks.red = r;
		m->ks.green = g;
		m->ks.blue = 0.0;

		m->kt.red = 1;
		m->kt.green = 1;
		m->kt.blue = 1;

		m->n = 400.0;
		// set spheres material
		s->setMaterial(m);
		// as sphere to scene
		scene->addObject(*s);
	}
}

void addSphereTexture(Scene *scene) {
	SphereTexture *s;
	Material *m;
	Vertex p;
	// position
	p.set(0.0, 0.0, 0.0, 1.0);
	s = new SphereTexture(p, 0.01,image);
	//	s->refraction = 1.53;// open refraction by set a refraction value. 1.53 is glass. 1.3 is water.
	// create new material with shared random Ka and Kd
	m = new Material();
	m->ka.red = 0.2;
	m->ka.green = 0.0;
	m->ka.blue = 0.0;
	m->kd.red = 0.0;
	m->kd.green = 0.0;
	m->kd.blue = 0.0;

	m->kr.red = 0.5;
	m->kr.green = 0.5;
	m->kr.blue = 0.5;

	m->ks.red = 0.5;
	m->ks.green = 0.5;
	m->ks.blue = 0.5;

	m->kt.red = 0.1;
	m->kt.green = 0.1;
	m->kt.blue = 0.1;

	m->n = 400.0;
	// set spheres material
	s->setMaterial(m);

	Rotation ro;
	ro.setx(3.1415926/2.0);
	s->addTransform(ro);

	// as sphere to scene
	scene->addObject(*s);
}

int main(int argc, const char *argv[]) {

	Scene *scene;
	Vector v;
	Vertex ppl;
	int x, y;
	int n;
	DirectionalLight *dl;
	PointlLight * pl;
	Colour cl, cpl;
	double ca, cr, cg, cb;

	srand(30115);

	clear_framebuffer();

	// SETUP SCENE

	// Create a new scene to render
	scene = new Scene();

	// The main light
	v.set(0, -3, 3);
	cl.set(1.0, 1.0, 1.0, 1.0);
	dl = new DirectionalLight(v, cl);
	scene->addLight(*dl);

//	//bottom directional light
	v.set(-1, 0, 3);
	cl.set(0.1, 0.1, 0.1, 1.0);
	DirectionalLight *dlbottom;
	dlbottom = new DirectionalLight(v, cl);
	scene->addLight(*dlbottom);

	//back directional light
//	v.set(1, 0, -3);
//	cl.set(0.8, 0.8, 0.8, 1.0);
//	DirectionalLight *dlback;
//	dlback = new DirectionalLight(v, cl);
//	scene->addLight(*dlback);

	//point light
	ppl.set(0, 5, 1, 1);
	cpl.set(31.0, 31.0, 31.0, 1.0);
	pl = new PointlLight(ppl, cpl);
	scene->addLight(*pl);

	// Add 10 random spheres to the scene
	for (n = 0; n < 0; n += 1) {
		Sphere *s;
		Material *m;
		Vertex p;

		// position
		p.set(frand() - 0.5, frand() - 0.5, frand() + 1.0, 1.0);

		// create with random radius
		s = new Sphere(p, frand() / 2.0);

		s->refraction = 1.53;// open refraction by set a refraction value. 1.53 is glass. 1.3 is water.

		//transform
		//				Scaling scaling;
		//				scaling.set(1.0,3.0,1.0);
		//				s->addTransform(scaling);
		//		//
		//				Rotation ro;
		//				ro.setz(0.8);
		//				s->addTransform(ro);

		//				Translation tra;
		//				tra.set(-0.3,0.6,0);
		//				s->addTransform(tra);

		// create new material with shared random Ka and Kd
		m = new Material();

		cr = frand();
		cg = frand();
		cb = frand();
		ca = frand();

		m->ka.red = 0.0;
		m->ka.green = 0.0;
		m->ka.blue = 0.0;
		m->kd.red = 0.0;
		m->kd.green = 0.0;
		m->kd.blue = 0.0;

		//		m->ka.red = cr * 0.1;
		//		m->ka.green = cg * 0.1;
		//		m->ka.blue = cb * 0.1;
		//		m->kd.red = cr * 0.5;
		//		m->kd.green = cg * 0.5;
		//		m->kd.blue = cb * 0.5;

		m->kr.red = 0.5;
		m->kr.green = 0.5;
		m->kr.blue = 0.5;

		m->ks.red = 0.5;
		m->ks.green = 0.5;
		m->ks.blue = 0.5;

		m->kt.red = 1;
		m->kt.green = 1;
		m->kt.blue = 1;

		m->n = 400.0;

		// set spheres material
		s->setMaterial(m);

		// as sphere to scene
		scene->addObject(*s);

	}


	image = readPPM("/Users/Peter/Documents/dev/workspaces/cpp_cdt/raytracer_Test/src/f.ppm");

	addPlane2(scene);
	addQuadricCone(scene);
	addQuadricConeW(scene);

	addQuadricCone2(scene);
	addSphereTrans(scene);



//	addTriangle(scene);
	addPlane(scene);
//////
//	addQuadricEllipsoid(scene);
//	addQuadricCylinder(scene);
////
//	addTriangleTexture(scene);
//	addQuadricCylinderTexture(scene);
//	addSphereTexture(scene);
////
//	addSphereRed(scene);
//	addSphereBlue(scene);
//	addSphereGreen(scene);
//	addBox(scene);


	// Camera
	Camera *camera = new Camera();
	camera->Eye.set(0.01, 0.1, 0.2, 1.0);
	camera->Look.set(0.0, -0.1, 1.0);
	camera->Up.set(0.0, 1.0, 1.0);
	camera->orthonormal();

	// RAYTRACE SCENE
	for (y = 0; y < YSIZE; y += 1) {
		for (x = 0; x < XSIZE; x += 1) {
			Ray ray;
			float d;

			if (x == 318 && y == 512 - 244) {//ok
				int aaaa = 0;
				aaaa = aaaa+aaaa;

			}
			//			if (x == 333 && y == 512 - 208) {//black
			//				int aaaa = 0;
			//			}
			// Calculate a primary ray

			//			ray = camera->generatePrimaryRay(x, y, XSIZE, YSIZE);
			//
			//			//      d = 0.5;
			//			//      ray.P.set(0.0,0.0,0.0,1.0);
			//			//      ray.D.set((((float)x)/XSIZE)-0.5, (((float)y)/XSIZE)-0.5, d);
			//			//      ray.D.normalise();
			//
			//			// Trace primary ray
			//			Colour col = scene->raytrace(ray, 6);


			Colour col = camera->PrimaryRayTracing(x, y, XSIZE, YSIZE, scene);

			// Save result in frame buffer
			frame_buffer[y][x].red = col.red;
			frame_buffer[y][x].green = col.green;
			frame_buffer[y][x].blue = col.blue;
			if (x == 414 && y == 512 - 229) {//ok
				//							frame_buffer[y][x].red = 111.0;
				//										frame_buffer[y][x].green = 0.0;
				//										frame_buffer[y][x].blue = 0.0;
			}
			if (x == 413 && y == 512 - 229) {//black
				//							frame_buffer[y][x].red = 0.0;
				//										frame_buffer[y][x].green = 0.0;
				//										frame_buffer[y][x].blue = 111;
			}
		}
	}

	// OUTPUT IMAGE

	write_framebuffer();
}

